/******************************************************************************
 cnome: A C++ source "genes" discover. :-)

 See more details at:

   http://www.codeplex.com/cnome

 The original author site is at: http://www.alemosbarbosa.com/

 Copyright (c) 2008-2010 Alexandre Lemos Barbosa.
 Distributed under the MIT License. (See accompanying file LICENSE-MIT.txt 
 or at http://www.codeplex.com/cnome/license)
 ******************************************************************************/

#ifndef DEFINITION_H
#define DEFINITION_H

#include <boost/wave/token_ids.hpp> 

#include "cnome.h"
#include "iterator.h"
#include "typedefs.h"
#include "symbol.h"
#include "tokens.h"

namespace cnome {
struct cpp : public boost::spirit::classic::grammar<cpp> {

//  static error_report_p error_syntax; 

    template <typename ScannerT>
    struct definition {
        definition(cpp const& self);
        void declarations(cpp const& self);
        void classes(cpp const& self);
        void expressions(cpp const& self);
        void declarators(cpp const& self);
        void statements(cpp const& self);
        void derived_classes(cpp const& self);
        void exception_handling(cpp const& self);
        void special_member_functions(cpp const& self);
        void overloading(cpp const& self);
        void templates(cpp const& self);

        rule_t const& start() const;

        // Rule declarations
        rule_t begin,
               translation_unit,
               declaration_seq,
               declaration_seq_helper,
               declaration,
               linkage_specification,
               template_declaration, 
               explicit_instantiation, 
               explicit_specialization, 
               block_declaration,
               asm_definition,
               namespace_alias_definition,
               qualified_namespace_specifier,
               simple_declaration,
               using_declaration,
               using_directive,
               namespace_definition,
               namespace_name,
               namespace_alias,
               named_namespace_definition,
               original_namespace_name,
               extension_namespace_definition, 
               unnamed_namespace_definition,
               namespace_body,
               original_namespace_definition,
               decl_specifier_seq,
               decl_specifier_seq_helper,
               decl_specifier,
               storage_class_specifier,
               function_specifier,
               type_specifier,
               enum_specifier,
               elaborated_type_specifier ,
               cv_qualifier,
               cv_qualifier_seq,
               template_id,
               enumerator_list,
               enumerator_list_helper,
               enumerator_definition,
               enumerator,
               constant_expression,
               simple_type_specifier,
               type_name,    
               typedef_name,
               enum_name,
               class_key,
               class_specifier,
               class_head,
               member_specification,
               member_declaration,
               member_declarator_list,
               member_declarator,
               member_declarator_list_helper,
               pure_specifier,
               constant_initializer,
               class_name,
               literal,
               logical_or_expression,
               logical_or_expression_helper,
               logical_and_expression,
               inclusive_or_expression,
               logical_and_expression_helper,
               exclusive_or_expression,
               inclusive_or_expression_helper,
               and_expression,
               exclusive_or_expression_helper,
               equality_expression,
               and_expression_helper,
               relational_expression,
               equality_expression_helper,
               shift_expression,
               relational_expression_helper,
               additive_expression,
               shift_expression_helper,
               multiplicative_expression,
               additive_expression_helper,
               pm_expression,
               pm_expression_helper,
               multiplicative_expression_helper,
               assignment_expression,
               assignment_operator,
               expression,
               expression_helper,
               condition_expression,
               unqualified_id,
               unqualified_id_raw,
               operator_function_id, // To be removed
               conversion_function_id, // To be removed
               id_expression,
               qualified_id,
               nested_name_specifier,
               class_or_namespace_name,
               expression_list,
               expression_list_helper,
               postfix_expression,
               post_fix_expression_a,
               post_fix_expression_helper,
               post_fix_expression_b,
               pseudo_destructor_name,
               new_declarator,
               direct_new_declarator,
               direct_new_declarator_helper,
               cast_expression,
               unary_operator,
               unary_expression,
               new_expression,
               delete_expression,
               new_placement,
               new_type_id,
               new_initializer,
               primary_expression,
               init_declarator_list,
               init_declarator,
               initializer,
               init_declarator_list_helper,
               initializer_clause,
               initializer_list,
               initializer_list_helper,
               function_definition,
               function_body,
               declarator,
               direct_declarator,
               declarator_id,
               direct_declarator_helper,
               type_id,
               abstract_declarator,
               direct_abstract_declarator,
               direct_abstract_declarator_helper,
               ptr_operator,
               type_specifier_seq,
               parameter_declaration_clause,
               parameter_declaration_list,
               parameter_declaration_list_helper,
               parameter_declaration,
               base_clause,
               base_specifier_list,
               base_specifier,
               base_specifier_list_helper,
               access_specifier,
               conditional_expression,
               try_block,
               handle_seq,
               function_try_block,
               handle,
               exception_declaration,
               throw_expression,
               type_id_list,
               type_id_list_helper,
               exception_specification,
               statement,
               labeled_statement,
               expression_statement,
               selection_statement,
               iteration_statement,
               jump_statement,
               declaration_statement,
               condition,
               for_init_statement,
               compound_statement,
               statement_seq,
               statement_seq_helper,
               conversion_type_id,
               conversion_declarator,
               ctor_initializer, 
               mem_initializer_list,
               mem_initializer,
               mem_initializer_list_helper,
               mem_initializer_id,
               operator_,
               template_parameter_list,
               template_parameter,
               template_parameter_list_helper,
               type_parameter,
               template_name,
               template_argument_list,
               template_argument,
               template_argument_list_helper,
               nested_name_specifier_a,
               nested_name_specifier_b;
    };

    cpp() {}
};

template <typename ScannerT> 
cpp::definition<ScannerT>::definition(cpp const& self) {
    begin = 
        translation_unit
    ;

    translation_unit =
        !declaration_seq
    ;

    declarations(self);
    classes(self);
    expressions(self);
    declarators(self);
    derived_classes(self);
    statements(self);
    exception_handling(self);
    special_member_functions(self);
    overloading(self);
    templates(self);
    //  End grammar definition
          
    // turn on the debugging info.
    BOOST_SPIRIT_DEBUG_RULE(begin);
    BOOST_SPIRIT_DEBUG_RULE(translation_unit);
    BOOST_SPIRIT_DEBUG_RULE(declaration_seq);
}

template <typename ScannerT> 
rule_t const&
cpp::definition<ScannerT>::start() const {         
    using namespace boost::wave;

     // Declaration of built-in types
    symbolPtr aux_char = symbolPtr(new symbol(token_t(T_CHAR    , "char"    , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["char"]     = aux_char;
    symbolPtr aux_uchar = symbolPtr(new symbol(token_t(T_CHAR    , "unsigned char"    , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["unsigned char"]     = aux_uchar;
    symbolPtr aux_schar = symbolPtr(new symbol(token_t(T_CHAR    , "signed char"    , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["signed char"]     = aux_schar;
    symbolPtr aux_wchar = symbolPtr(new symbol(token_t(T_WCHART  , "wchar_t" , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["wchar_t"]  = aux_wchar;
    symbolPtr aux_bool = symbolPtr(new symbol(token_t(T_BOOL    , "bool"    , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["bool"]     = aux_bool;
    symbolPtr aux_short = symbolPtr(new symbol(token_t(T_SHORT   , "short"   , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["short"]    = aux_short;
    symbolPtr aux_ushort = symbolPtr(new symbol(token_t(T_SHORT    , "unsigned short"    , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["unsigned short"]     = aux_ushort;
    symbolPtr aux_sshort = symbolPtr(new symbol(token_t(T_SHORT    , "signed short"    , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["signed short"]     = aux_sshort;
    symbolPtr aux_int = symbolPtr(new symbol(token_t(T_INT     , "int"     , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["int"]      = aux_int;
    symbolPtr aux_uint = symbolPtr(new symbol(token_t(T_INT    , "unsigned int"    , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["unsigned int"]     = aux_uint;
    symbolPtr aux_sint = symbolPtr(new symbol(token_t(T_INT    , "signed int"    , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["signed int"]     = aux_sint;
    symbolPtr aux_shint = symbolPtr(new symbol(token_t(T_INT     , "short int"     , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["short int"]      = aux_shint;
    symbolPtr aux_sshint = symbolPtr(new symbol(token_t(T_INT     , "signed short int"     , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["signed short int"]      = aux_sshint;
    symbolPtr aux_ushint = symbolPtr(new symbol(token_t(T_INT     , "unsigned short int"     , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["unsigned short int"]      = aux_ushint;
    symbolPtr aux_long = symbolPtr(new symbol(token_t(T_LONG    , "long"    , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["long"]     = aux_long;
    symbolPtr aux_ulong = symbolPtr(new symbol(token_t(T_LONG    , "unsigned long"    , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["unsigned long"]     = aux_ulong;
    symbolPtr aux_slong = symbolPtr(new symbol(token_t(T_LONG    , "signed long"    , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["signed long"]     = aux_slong;
    symbolPtr aux_longi = symbolPtr(new symbol(token_t(T_LONG    , "long int"    , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["long int"]     = aux_longi;
    symbolPtr aux_ulongi = symbolPtr(new symbol(token_t(T_LONG    , "unsigned long int"    , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["unsigned long int"]     = aux_ulongi;
    symbolPtr aux_longlong = symbolPtr(new symbol(token_t(T_LONG    , "long long"    , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["long long"]     = aux_longlong;
    symbolPtr aux_longlongi = symbolPtr(new symbol(token_t(T_LONG    , "long long int"    , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["long long int"]     = aux_longlongi;
    symbolPtr aux_slongi = symbolPtr(new symbol(token_t(T_LONG    , "signed long int"    , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["signed long int"]     = aux_longi;
    symbolPtr aux_signed = symbolPtr(new symbol(token_t(T_SIGNED  , "signed"  , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["signed"]   = aux_signed;
    symbolPtr aux_unsigned = symbolPtr(new symbol(token_t(T_UNSIGNED, "unsigned", boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["unsigned"] = aux_unsigned;
    symbolPtr aux_float = symbolPtr(new symbol(token_t(T_FLOAT   , "float"   , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["float"]    = aux_float;
    symbolPtr aux_double = symbolPtr(new symbol(token_t(T_DOUBLE  , "double"  , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["double"]   = aux_double;
    symbolPtr aux_ldouble = symbolPtr(new symbol(token_t(T_DOUBLE  , "long double"  , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["long double"]   = aux_ldouble;
    symbolPtr aux_void = symbolPtr(new symbol(token_t(T_VOID    , "void"    , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["void"]     = aux_void;
    symbolPtr aux_ellipsis = symbolPtr(new symbol(token_t(T_ELLIPSIS   , "..."    , boost::wave::cpplexer::lex_token<>::position_type()), symbol::keyword, -1));
    cnome_symbols["..."]     = aux_ellipsis;

    return begin; 
}

extern cpp const cnome_p;
}  // namespace cnome

#endif // DEFINITION_H
